<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="box">
    {{ aaa}}
    卧槽
    <div>
        <p>asdasd</p>
        啊实打实的
        <span>6666</span>
    </div>
    {{bbb}}
    我擦勒哦
    <br>
    <button :title="bbb * 10" -click="handleClick">点我</button>
    <input :value="value" type="text">
</div>
<script>

    function getRoot(root){
        assert(root,"root 有问题")
        if( typeof root === "string"){
            return document.querySelector(root) || assert(root,"root 有问题")
        }else if( root instanceof HTMLElement){
            return root
        }else{
            assert(root,"root 有问题")
        }
    }
    function assert(exp,msg){
        if( !exp ){
            throw new Error(msg)
        }
        return true
    }
    class Vue {
        constructor(options) {
            this._root = getRoot(options.root)
            this.timer = null
            assert(options.data)
            let data = null
            if( typeof options.data === 'function'){
                data = options.data() || {}
            }else{
                data = options.data || {}
            }

            const proxy = new Proxy(data,{
                set:(target, p, value)=> {
                    console.log(target)
                    this.update()
                    target[p] = value
                    return true
                }
            })
            // this._template = document.createDocumentFragment();
            // this._template.append(this._root)
            this._template = this._root.cloneNode(true)
            this._parent = this._root.parentNode;
            // 初始渲染
            this.update()
            this._data = proxy
            this._methods = options.methods || {}
            return proxy;
        }
        update(){
            clearTimeout(this.timer)
            this.timer = setTimeout(()=>{
                this.render()
            },0)
        }
        render(){
            // console.log("render")
            let root = this._template.cloneNode(true)
            const that = this;
            function handleTxt(node){
                node.childNodes.forEach(e=>{
                    if( e.nodeType === document.TEXT_NODE ){
                        e.data = e.data.replace(/\{\{[^\}]+\}\}/g,(str)=>{
                            str = str.substring(2, str.length - 2).trim()
                            let arr = []
                            for (const dataKey in that._data) {
                                arr.push(`let ${dataKey} = ${JSON.stringify(that._data[dataKey])};`)
                            }
                            arr.push(str)
                            return eval(arr.join(''))
                        })
                    }else if(e.nodeType === document.ELEMENT_NODE){
                        handleTxt(e)
                    }
                })
            }
            handleTxt(root)

            Array.from(root.childNodes).forEach(e=>{
                if(e.nodeType === document.ELEMENT_NODE){
                    Array.from(e.attributes).forEach(evenName=>{
                        if( evenName.name.startsWith("-") ){
                            const name = evenName.name.substring(1,evenName.name.length);
                            e.addEventListener(name,that._methods[evenName.value].bind(that._data))
                        }
                        if(evenName.name.startsWith(":")){
                            const name = evenName.name.substring(1,evenName.name.length);
                            let arr = []
                            for (let dataKey in that._data) {
                                arr.push(`let ${dataKey} = ${JSON.stringify(that._data[dataKey])};`)
                            }
                            arr.push(evenName.value)
                            e[name] = eval(arr.join(''))
                        }
                    })
                }
            })
            this._parent.replaceChild(root,this._root)
            this._root = root
        }
    }
    const vue = new Vue({
        root:document.querySelector('#box'),
        data(){
            return{
                aaa:"被编译出来的",
                bbb:2,
                value:"绑定到input"
            }
        },
        methods:{
            handleClick(){
                this.bbb += 5
            }
        }
    })






</script>
</body>
</html>